package com.LachesismStorm.lachesism.websocket;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@ServerEndpoint("/fileTransfer")
@Component
@Slf4j
public class FileTransferWebSocketService {

    /**
     * 存储所有WebSocket会话
     * Key: sessionId
     * Value: WebSocket Session对象
     */
    private static final ConcurrentHashMap<String, Session> sessionMap = new ConcurrentHashMap<>();

    /**
     * 存储设备信息
     * Key: deviceId
     * Value: 设备信息（包含id, name, ip, port）
     */
    private static final ConcurrentHashMap<String, JSONObject> deviceInfoMap = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session) {
        log.info("新的WebSocket连接建立: {}", session.getId());
        sessionMap.put(session.getId(), session);
        // 新连接时请求设备列表
        requestDeviceList(session);
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        try {
            JSONObject json = JSONUtil.parseObj(message);
            String type = json.getStr("type");

            switch (type) {
                case "announce":
                    handleAnnounce(json, session);
                    break;
                case "offer":
                    handleOffer(json);
                    break;
                case "answer":
                    handleAnswer(json);
                    break;
                case "ice-candidate":
                    handleIceCandidate(json);
                    break;
                case "requestDeviceList":
                    handleRequestDeviceList(session);
                    break;
                case "chat":
                    handleChatMessage(json); // 处理聊天消息
                    break;
                default:
                    log.warn("收到未知类型的消息: {}", type);
            }
        } catch (Exception e) {
            log.error("处理WebSocket消息时发生错误", e);
        }
    }

    @OnClose
    public void onClose(Session session) {
        log.info("WebSocket连接关闭: {}", session.getId());
        // 移除会话和设备信息
        sessionMap.remove(session.getId());
        deviceInfoMap.remove(session.getId());
        // 广播更新后的设备列表
        broadcastDeviceList();
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("WebSocket发生错误: {}", session.getId(), error);
    }

    /**
     * 处理设备公告消息
     */
    private void handleAnnounce(JSONObject json, Session session) {
        JSONObject deviceInfo = json.getJSONObject("device");
        deviceInfoMap.put(deviceInfo.getStr("id"), deviceInfo); // 使用设备ID作为唯一标识
        broadcastDeviceList();
        log.info("设备已注册: {}", deviceInfo);
    }

    /**
     * 处理WebRTC Offer
     */
    private void handleOffer(JSONObject json) {
        String targetId = json.getStr("targetId");
        forwardToDevice(targetId, json);
    }

    /**
     * 处理WebRTC Answer
     */
    private void handleAnswer(JSONObject json) {
        String targetId = json.getStr("targetId");
        forwardToDevice(targetId, json);
    }

    /**
     * 处理ICE Candidate
     */
    private void handleIceCandidate(JSONObject json) {
        String targetId = json.getStr("targetId");
        forwardToDevice(targetId, json);
    }

    /**
     * 处理聊天消息
     */
    private void handleChatMessage(JSONObject json) {
        String targetId = json.getStr("targetId");
        String messageContent = json.getStr("message");
        JSONObject chatMessage = new JSONObject();
        chatMessage.put("from", json.getStr("from"));
        chatMessage.put("message", messageContent);

        forwardToDevice(targetId, chatMessage); // 将聊天消息转发给目标设备
        log.info("聊天消息发送: {}", chatMessage);
    }

    /**
     * 转发消息给指定设备
     */
    private void forwardToDevice(String targetId, JSONObject message) {
        Session targetSession = findSessionByDeviceId(targetId);
        if (targetSession != null && targetSession.isOpen()) {
            try {
                targetSession.getBasicRemote().sendText(message.toString());
            } catch (IOException e) {
                log.error("转发消息失败", e);
            }
        } else {
            log.warn("目标设备不可用: {}", targetId);
        }
    }

    /**
     * 通过设备ID查找Session
     */
    private Session findSessionByDeviceId(String targetId) {
        for (Map.Entry<String, Session> entry : sessionMap.entrySet()) {
            JSONObject deviceInfo = deviceInfoMap.get(entry.getKey());
            if (deviceInfo != null && targetId.equals(deviceInfo.getStr("id"))) {
                return entry.getValue();
            }
        }
        return null;
    }

    /**
     * 广播设备列表给所有连接的客户端
     */
    private void broadcastDeviceList() {
        JSONObject message = new JSONObject();
        message.put("type", "deviceList");
        List<JSONObject> devices = new ArrayList<>(deviceInfoMap.values());
        message.put("devices", devices);

        String messageStr = message.toString();
        for (Session session : sessionMap.values()) {
            if (session.isOpen()) {
                try {
                    // 检查连接状态并广播
                    session.getBasicRemote().sendText(messageStr);
                } catch (IOException e) {
                    log.error("广播设备列表失败", e);
                }
            }
        }
    }

    /**
     * 处理请求设备列表的消息
     */
    private void handleRequestDeviceList(Session session) {
        JSONObject message = new JSONObject();
        message.put("type", "deviceList");
        List<JSONObject> devices = new ArrayList<>(deviceInfoMap.values());
        message.put("devices", devices);

        try {
            session.getBasicRemote().sendText(message.toString());
            log.info("已发送设备列表给客户端: {}", session.getId());
        } catch (IOException e) {
            log.error("发送设备列表失败", e);
        }
    }

    /**
     * 请求设备列表（客户端连接时调用）
     */
    private void requestDeviceList(Session session) {
        JSONObject message = new JSONObject();
        message.put("type", "requestDeviceList");
        try {
            session.getBasicRemote().sendText(message.toString());
        } catch (IOException e) {
            log.error("请求设备列表失败", e);
        }
    }

    /**
     * 发送消息给指定会话
     */
    private void sendMessage(Session session, String message) {
        try {
            session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            log.error("发送消息失败", e);
        }
    }

    /**
     * 获取当前连接的设备数量
     */
    public static int getConnectedDeviceCount() {
        return deviceInfoMap.size();
    }

    /**
     * 获取所有设备信息
     */
    public static List<JSONObject> getAllDevices() {
        return new ArrayList<>(deviceInfoMap.values());
    }
}
